import getAstsdk from "ast_sdk";
import dayjs from "dayjs";
import deviceKeyValueDB from "../../../database/deviceKeyValueDB/deviceKeyValueDB";
import orgApi from "../../../apis/orgApis/orgApi";

class BalanceBaseUtils {
  // 构造器
  constructor() {}

  // key = bizUncode = balance_no = 业务唯一码
  key = "";
  defaultKey = "";
  //加密后的key
  encKey = "";

  // 获取流程： localstorege -> sdk -> 后台 -> ''
  asyncGetKey = async () => {
    try {
      // storege没有就从sdk获取
      const { deviceUncode, bizUncode } = await getAstsdk()
        .getInfo()
        .getBaseInfo();
      if (bizUncode) {
        // localStorage.setItem('wl-bizUncode', bizUncode)
        // 同时也写入数据库
        await deviceKeyValueDB.setItem("wl-bizUncode", bizUncode);
        this.key = bizUncode;
        return bizUncode;
      }
      // sdk没有就从后台获取
      try {
        const result = await orgApi.getBalanceNo({ uniqueCode: deviceUncode });
        if (result?.data?.balance_no) {
          // localStorage.setItem('wl-bizUncode', result.data.balance_no)
          // 同时也写入数据库
          await deviceKeyValueDB.setItem(
            "wl-bizUncode",
            result.data.balance_no
          );
          this.key = result.data.balance_no;

          /* 
          这里是因为,虽然现在没启动加密,
          但是后台说新机必须获取一次加密key(可以重复获取),
          我们没法知道是不是新机,所以只能每次加载key 的时候 请求loadkey.
          但是为了性能问题,就让他如果有key就不请求了 
        */
          if (!this.encKey) {
            const result = await orgApi.loadKey({
              key: this.key,
              isLoad: 1,
            });
            if (result.data) {
              this.encKey = result.data;
            } else {
              this.encKey = "";
            }
          }
          return this.key;
        }
      } catch (error) {
        console.error("获取业务码失败", error);
      }

      // 先从localstorege获取
      // const storegeBizUncode = localStorage.getItem('wl-bizUncode')
      // 从数据库获取
      const dbBizUncode = await deviceKeyValueDB.getItem("wl-bizUncode");
      const storegeBizUncode = dbBizUncode;

      if (storegeBizUncode) {
        this.key = storegeBizUncode;
        return storegeBizUncode;
      }

      this.key = "";
      return this.key;
    } catch (e) {
      console.error(e);
      this.key = "";
      return this.key;
    }
  };
  getKey = () => {
    return this.key;
  };

  // 是否已经同步过时间
  isSyncTime = false;
  // 定时器
  syncTimeInterval: ReturnType<typeof setInterval> | null = null;
  private disTime = 0;

  // 软件启动的时间戳 1761187207466.1 毫秒级 也就是 2025-10-23 10:40:07 建议向下取整
  // private startTimestamp = Math.floor(performance.timeOrigin)

  // 时间错误的根本原因： 因为没有网络会一直调用asyncTime，每次调用就会将this.disTime（本应为软件启动的时间） 重置为最新时间。
  asyncTime = async () => {
    try {
      // 请求开始时间机器运行时间
      try {
        const requestStartTime = Math.floor(performance.now());
        const result = await orgApi.getTime();

        if (result.res !== 1) {
          throw new Error("获取时间失败");
        } else {
          // 如果请求成功, 设置同步时间
          this.isSyncTime = true;
          // 服务器时间
          const serverTime = result.servertime;
          // 请求结束时间机器运行时间
          const requestEndTime = Math.floor(performance.now());
          // 计算请求花费时间 = (请求结束后机器运行时间 - 请求开始前机器运行时间)/2
          const consumeTime = Math.floor(
            (requestEndTime - requestStartTime) / 2
          );
          // 当前机器运行时间
          const currentTime = Math.floor(performance.now());
          // 服务器真正的当前时间 = 服务器时间 + 请求花费时间
          const serverCurTime = serverTime + consumeTime;
          // 服务器比程序运行时间快多少 = 服务器真正的当前时间 - 当前机器运行时间
          // 以后要获取是服务器时间就是  服务器比程序运行时间快多少 + 当前时间机器运行时间（performance.now()）就可以得到
          this.disTime = serverCurTime - currentTime;
        }
      } catch (e) {
        // 清楚上一个定时器
        if (this.syncTimeInterval) {
          clearInterval(this.syncTimeInterval);
        }
        // 重新设置定时器
        this.syncTimeInterval = setTimeout(() => {
          this.asyncTime();
        }, 3000);
        return;
      }
    } catch (e) {
      console.log(e);
    }
  };

  // 时间戳(毫秒)
  getTime = () => {
    // 软件启动的时间戳 + 服务器比程序运行时间快多少 + 程序运行时间 = 当前服务器时间
    // 有网络的时候使用服务器的时间， 有无网络就看有没有 this.disTime 因为this.disTime 是服务器获取的
    if (this.disTime) {
      return this.disTime + Math.floor(performance.now());
    }
    // 无网络使用当前时间
    return dayjs().valueOf();
  };
}

const balanceBaseUtils = new BalanceBaseUtils();
(window as any).balanceBaseUtils = balanceBaseUtils;
export default balanceBaseUtils;
